

package utils

import (
	"bytes"
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/binary"
	"encoding/gob"
	"encoding/hex"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/qit-team/snow-core/log/logger"
	"golang.org/x/crypto/bcrypt"
	"hash/crc32"
	"math"
	"math/big"
	"math/rand"
	"sort"

	"encoding/xml"
	"runtime"
	"strconv"
	"strings"
	"time"
)

const CODE62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const codeLen = 20

var doc = map[string]int64{"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9, "a": 10, "b": 11, "c": 12, "d": 13, "e": 14, "f": 15, "g": 16, "h": 17, "i": 18, "j": 19, "k": 20, "l": 21, "m": 22, "n": 23, "o": 24, "p": 25, "q": 26, "r": 27, "s": 28, "t": 29, "u": 30, "v": 31, "w": 32, "x": 33, "y": 34, "z": 35, "A": 36, "B": 37, "C": 38, "D": 39, "E": 40, "F": 41, "G": 42, "H": 43, "I": 44, "J": 45, "K": 46, "L": 47, "M": 48, "N": 49, "O": 50, "P": 51, "Q": 52, "R": 53, "S": 54, "T": 55, "U": 56, "V": 57, "W": 58, "X": 59, "Y": 60, "Z": 61}

func GetLimitStart(limit int, page int) (arr []int) {
	arr = make([]int, 2)
	if limit <= 0 {
		limit = 20
	}
	arr[0] = limit
	if page > 0 {
		arr[1] = (page - 1) * limit
	} else {
		arr[1] = 0
	}
	return
}

//MD5加密
func SToMd5(data string) string {
	r := md5.Sum([]byte(data))
	return hex.EncodeToString(r[:])

}

//Hash加密
func SToHash(data string) string {
	hash, _ := bcrypt.GenerateFromPassword([]byte(data), bcrypt.DefaultCost)
	return string(hash)
}

//深层拷贝
func DeepCopy(dst, src interface{}) error {
	var buf bytes.Buffer
	if err := gob.NewEncoder(&buf).Encode(src); err != nil {
		return err
	}
	return gob.NewDecoder(bytes.NewBuffer(buf.Bytes())).Decode(dst)
}

/**
 * 编码 整数 为 base62 字符串
 */
func Encode(number int64) string {
	if number == 0 {
		return "0"
	}
	result := make([]byte, 0)
	for number > 0 {
		round := number / codeLen
		remain := number % codeLen
		result = append(result, CODE62[remain])
		number = round
	}
	return string(result)
}

/**
 * 解码字符串为整数
 */
func Decode(str string) int64 {
	str = strings.TrimSpace(str)
	var result int64 = 0
	for index, char := range []byte(str) {
		result += doc[string(char)] * int64(math.Pow(codeLen, float64(index)))
	}
	return result
}

func StingToInt64(param string) int64 {
	rs, err := strconv.ParseInt(param, 10, 64)
	if err != nil {
		logger.Debug(nil, "sti64err", err)
	}
	return rs
}

func GetOrderId(salt int64) string {
	//timeLayout := "2006-01"  //转化所需模板
	//var datetime = time.Unix(time.Now().Unix(), 0).Format(timeLayout)+"-"
	timeStr := time.Now().Format("20060102150405")
	microTime := strconv.FormatInt(time.Now().UnixNano()/1000000, 10)
	timeStr += microTime[len(microTime)-3:]
	rand.Seed(time.Now().UnixNano())
	timeStr += Encode(int64(rand.Intn(100000)))
	return timeStr + strconv.FormatInt(salt, 10)
}
func GetThisDay() string {
	timeLayout := "2006-01-01" //转化所需模板
	var datetime = time.Unix(time.Now().Unix(), 0).Format(timeLayout) + "-"
	return datetime
}
func Log(c *gin.Context, name string, msg ...interface{}) {
	_, file, line, _ := runtime.Caller(1)
	timeLayout := "2006-01-01 03:04:05" //转化所需模板
	var datetime = time.Unix(time.Now().Unix(), 0).Format(timeLayout)
	fmt.Println(name, msg, file, line, datetime)
}

func Float32ToByte(float float32) []byte {
	bits := math.Float32bits(float)
	bytes := make([]byte, 4)
	binary.LittleEndian.PutUint32(bytes, bits)

	return bytes
}

func ByteToFloat32(bytes []byte) float32 {
	bits := binary.LittleEndian.Uint32(bytes)

	return math.Float32frombits(bits)
}

func Float64ToByte(float float64) []byte {
	bits := math.Float64bits(float)
	bytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(bytes, bits)

	return bytes
}

func ByteToFloat64(bytes []byte) float64 {
	bits := binary.LittleEndian.Uint64(bytes)

	return math.Float64frombits(bits)
}
func Int64ToBytes(i int64) []byte {
	var buf = make([]byte, 8)
	binary.LittleEndian.PutUint64(buf, uint64(i))
	return buf
}

func BytesToInt64(buf []byte) int64 {
	return int64(binary.LittleEndian.Uint64(buf))
}
func IntToBytes(i int32) []byte {
	var buf = make([]byte, 4)
	binary.LittleEndian.PutUint32(buf, uint32(i))
	return buf
}

func BytesToInt(buf []byte) int {
	return int(binary.LittleEndian.Uint32(buf))
}

func Int16ToBytes(i int16) []byte {
	var buf = make([]byte, 2)
	binary.LittleEndian.PutUint16(buf, uint16(i))
	return buf
}

func BytesToInt16(buf []byte) int {
	return int(binary.LittleEndian.Uint16(buf))
}

func GetRealKey(key string) string {
	return  key
}

//排序字符串
func SortMap(param map[string]string) string {
	var sortStr = ""
	if len(param) > 0 {
		var keys = make([]string, 0)
		for k, _ := range param {
			keys = append(keys, k)
		}
		sort.Strings(keys)
		for _, v := range keys {
			if param[v] == "" {
				continue
			}
			sortStr += v + "=" + param[v] + "&"
		}
		sortStr = sortStr[0 : len(sortStr)-1]
	}
	return sortStr
}
func SortMapInterface(param map[string]interface{}) string {
	var sortStr = ""
	if len(param) > 0 {
		var keys = make([]string, 0)
		for k, _ := range param {
			keys = append(keys, k)
		}
		sort.Strings(keys)
		for _, v := range keys {
			if param[v] == "" {
				continue
			}
			if v == "time"{
				oldNum := float64(param[v].(float64))
				newNum := big.NewRat(1, 1)
				newNum.SetFloat64(oldNum)
				param[v] =newNum.FloatString(0)
			}
			//sortStr += v + "=" + param[v] + "&"
			sortStr += v + "=" + fmt.Sprintf("%v",param[v]) + "&"
		}
		sortStr = sortStr[0 : len(sortStr)-1]
	}
	return sortStr
}


func SortMapByLong(param map[string]string) string {
	var sortStr = ""
	if len(param) > 0 {
		var keys = make([]string, 0)
		for k, _ := range param {
			keys = append(keys, k)
		}
		sort.Strings(keys)
		for _, v := range keys {
			if param[v] == "" {
				continue
			}
			sortStr += "|" + param[v]
		}
		sortStr = sortStr[0 : len(sortStr)-1]
	}
	return sortStr
}
func DateStr(str string) string {
	if str == "" {
		str = "2006-01-02 15:04:05"
	}
	var datetime = time.Unix(time.Now().Unix()-3600, 0).Format(str)
	return datetime
}
func RandomNumber(start int, end int) string {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	var ranInt = r.Intn(end-start) + start
	return strconv.Itoa(ranInt)
}


func GetSHA256HashCode(message []byte) string {
	//方法一：
	//创建一个基于SHA256算法的hash.Hash接口的对象
	hash := sha256.New()
	//输入数据
	hash.Write(message)
	//计算哈希值
	bytes := hash.Sum(nil)
	//将字符串编码为16进制格式,返回字符串
	hashCode := hex.EncodeToString(bytes)
	//返回哈希值
	return hashCode

	//方法二：
	//bytes2:=sha256.Sum256(message)//计算哈希值，返回一个长度为32的数组
	//hashcode2:=hex.EncodeToString(bytes2[:])//将数组转换成切片，转换成16进制，返回字符串
	//return hashcode2
}
func GetSHA512HashCode(message []byte) string {

	hash := sha512.New()
	hash.Write(message)
	bytes := hash.Sum(nil)
	hashCode := hex.EncodeToString(bytes)
	return hashCode
}
func CRC32(str string) uint32 {
	return crc32.ChecksumIEEE([]byte(str))
}
func ParseXml(content string, data interface{}) error {
	err := xml.Unmarshal([]byte(content), &data)
	return err
}
func RandomName(min int, max int) string {
	rand.Seed(time.Now().UnixNano())
	var l = rand.Intn(max-min) + min
	fmt.Println(l)
	str := "abcdefghijklmnopqrstuvwxyz"
	strBig := "ABCDEFGHIGKLMNOPQRSTUVWXYZ"
	bytes := []byte(str)
	result := []byte{}
	for i := 0; i < l; i++ {
		if i == 0 {
			result = append(result, []byte(strBig)[rand.Intn(len(strBig))])
		} else {
			result = append(result, bytes[rand.Intn(len(bytes))])
		}

	}
	return string(result)
}

func GenEmail() string {
	rand.Seed(time.Now().UnixNano())
	var prefis = []string{"@gmail.com", "@yahoo.com", "@msn.com", "@hotmail.com", "@aol.com", "@ask.com", "@live.com", "@0355.net", "@yeah.net", "@googlemail.com", "@126.com", "@sina.com", "@sohu.com"}
	var lenth = rand.Intn(6) + 4
	var name = ""
	var keys = []string{}
	for k, _ := range doc {
		keys = append(keys, k)
	}
	for i := 0; i < lenth; i++ {
		var char = rand.Intn(len(prefis))
		name += keys[char]
	}
	var prefix = prefis[rand.Intn(len(prefis))]
	return name + prefix
}

func GenIpaddr() string {
	rand.Seed(time.Now().Unix())
	ip := fmt.Sprintf("%d.%d.%d.%d", rand.Intn(255), rand.Intn(255), rand.Intn(255), rand.Intn(255))
	return ip
}
func GetQuery(c *gin.Context,param []string) map[string]string {
	var rs  = make(map[string]string)
	for _,v := range param{
		rs[v],_ = c.GetQuery(v)
	}
	return rs
}


func HmacSha256(data string, secret string) string {
	h := hmac.New(sha256.New, []byte(secret))
	h.Write([]byte(data))
	return hex.EncodeToString(h.Sum(nil))
}

func DecodeMessage(message []byte) (int,[]byte) {
	var msgId = BytesToInt(message[0:4])
	return msgId,message[4:]
}

func PackMsg(message []byte,msgId int) []byte {
	var trasMessage = make([]byte,0)
	trasMessage = append(trasMessage,IntToBytes(int32(msgId))...)
	trasMessage = append(trasMessage,message...)
	return trasMessage
}